using System;
using Unity.Collections;
using UnityEngine;

namespace AnimCollections {
    public unsafe struct DynamicBlackboard : IDisposable {

        public static readonly int entrySize = 8; // 每个参数占用相同大小，按最大的来，目前最大vector2
        private int size; // 字节数

        byte* head; // buffer指针
        public byte* writePosition; // 此block中下一个被写入的位置
        public byte* blockEnd; // 最后一个字节，这个位置是可用的（包含）

        public bool isFull => writePosition > blockEnd;
        public ulong baseAddr => (ulong)head;
        public bool isValid => head != null;

        /// <param name="count">参数数量</param>
        public DynamicBlackboard(int count) {
            size = count * entrySize;
            head = null;
            writePosition = null;
            blockEnd = null;
            Malloc(size);
        }

        public void Dispose() {
            Memory.Unmanaged.Array.Resize(head, size, 0, Allocator.Persistent, 1, 8);
            head = null;
            writePosition = null;
            blockEnd = null;
        }

        public ulong Allocate() {
            if (writePosition > blockEnd) {
                // 已经填满
                // throw new OutOfMemoryException("容器已经填满");
                Debug.Log($"DBB 扩容，{size} -> {size * 2}");
                Resize(size * 2);
                return Allocate();
            }
            byte* pos = writePosition;
            writePosition += entrySize;
            Unity.Collections.LowLevel.Unsafe.UnsafeUtility.MemClear(pos, entrySize);
            return (ulong)pos;
        }

        /// <param name="newSize">字节数</param>
        void Malloc(int newSize) {
            head = (byte*)Memory.Unmanaged.Array.Resize(null, 0, newSize, Allocator.Persistent, 1, 8);
            blockEnd = head + newSize - sizeof(byte*);
            writePosition = head;
            size = newSize;
        }
        public void Clear() {
            writePosition = head;
        }
        void Resize(int newSize) {
            var oldCap = writePosition - head;
            head = (byte*)Memory.Unmanaged.Array.Resize(head, size, newSize, Allocator.Persistent, 1, 8);
            blockEnd = head + newSize - sizeof(byte*);
            writePosition = head + oldCap;
            size = newSize;
        }
    }
}
